package other.xsy.pms;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.rkhd.platform.sdk.api.annotations.*;
import com.rkhd.platform.sdk.context.ScriptRuntimeContext;
import com.rkhd.platform.sdk.data.model.*;
import com.rkhd.platform.sdk.exception.ApiEntityServiceException;
import com.rkhd.platform.sdk.exception.XsyHttpException;
import com.rkhd.platform.sdk.log.Logger;
import com.rkhd.platform.sdk.log.LoggerFactory;
import com.rkhd.platform.sdk.model.BatchOperateResult;
import com.rkhd.platform.sdk.model.XObject;
import com.rkhd.platform.sdk.service.XoqlService;
import org.apache.commons.lang.StringUtils;
import other.xsy.pms.utils.ComUtils;
import other.xsy.pms.utils.HCXObjectService;
import other.xsy.pms.utils.PromotionApiUtil;
import other.xsy.pms.utils.ResultVo;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: PMS 连接CRM api
 * @Author: 黎炎松
 * @Date: 2024/6/6 16:07
 */
@RestApi(baseUrl = "/pms")
public class PMSClientApi {
    private static HCXObjectService hcxObjectService = new HCXObjectService();
    private static final Logger logger = LoggerFactory.getLogger();

    public static void main(String[] args) throws Exception {
        HCXObjectService.isLocal = true;
        PMSClientApi pmsClientApi = new PMSClientApi();

        String jsonStr = "";

        // 设置项目预算信息 交付清单明细
        //jsonStr = "{\"grossProfitMarginCount\":0.3093,\"opportunityId\":\"3465585069857363\",\"netProfitContributedByTheProject\":0.2310,\"orderId\":\"3520985735256729\",\"preEstimateList\":[{\"deliveryClass\":\"服务_开发实施服务\",\"saleContractNo\":\"GCES-2024-1031-01\",\"productProperties\":\"公司自有IP\",\"productMaterial\":\"应用-后道MES-服务_开发实施服务，公司自有IP\",\"totalPrice\":\"1252358.49\",\"productCategoryL2\":\"后道MES\",\"productCategoryL1\":\"应用\",\"productPropertiesCode\":\"1001\",\"totalPriceTax\":\"1327500\",\"productCategoryL1Code\":\"11\",\"taxRate\":\"6%\",\"productMaterialNo\":\"11301202001\"," +
        //        "\"productCategoryL2Code\":\"11301\",\"deliveryClassCode\":\"11301202\"},{\"deliveryClass\":\"软件_买断式LICENSE\",\"saleContractNo\":\"GCES-2024-1031-02\"," +
        //        "\"productProperties\":\"公司自有IP\",\"productMaterial\":\"应用-后道MES-软件_买断式License，公司自有IP\",\"totalPrice\":\"265486.73\",\"productCategoryL2\":\"后道MES\",\"productCategoryL1\":\"应用\",\"productPropertiesCode\":\"1001\",\"totalPriceTax\":\"300000\",\"productCategoryL1Code\":\"11\",\"taxRate\":\"13%\",\"productMaterialNo\":\"11301101001\",\"productCategoryL2Code\":\"11301\",\"deliveryClassCode\":\"11301101\"}],\"rebate\":\"true\",\"projectContributionRate\":350588.59,\"deliveryNo\":\"F101242704D\",\"rebateFee\":\"75000\",\"grossProfitCount\":469445.22,\"rebateFeeRatio\":\"0.0494\"}";
        //pmsClientApi.setOrderBudgetInfo(JSONObject.parseObject(jsonStr));

        // 批量修改项目应收信息 里程碑
        //jsonStr = "{\"F102242496D\":[{\"planFinishTime\":\"1717862400000\",\"projectNo\":\"F102242496D\",\"milestoneName\":\"召开项目启动会\",\"actualFinishTime\":\"1717344000000\"},{\"planFinishTime\":\"1718121600000\",\"projectNo\":\"F102242496D\",\"milestoneName\":\"蓝图确认\",\"actualFinishTime\":\"1718121600000\"},{\"planFinishTime\":\"1725465600000\",\"projectNo\":\"F102242496D\",\"milestoneName\":\"项目转质保/关闭\",\"actualFinishTime\":\"1725292800000\"},{\"planFinishTime\":\"1722355200000\",\"projectNo\":\"F102242496D\",\"milestoneName\":\"项目验收\",\"actualFinishTime\":\"1725292800000\"},{\"planFinishTime\":\"1722355200000\",\"projectNo\":\"F102242496D\",\"milestoneName\":\"项目转质保/关闭\",\"actualFinishTime\":\"1720022400000\"}]}";
        //pmsClientApi.setProjectReceivables(JSONObject.parseObject(jsonStr));

        // 获取业务机会概算信息
        //String pmsEstimateData = pmsClientApi.getPmsEstimateData(3587533096344235L, null, null);
        //System.out.println("pmsEstimateData = " + pmsEstimateData);

        // 修改业务机会
        //jsonStr = "{\"pmsProjectCode__c\":\"F102244930D\",\"projectName__c\":\"潜在客户测试091101\",\"ProjectDeliveryDtatus__c\":\"已立项\",\"PMName__c\":\"朱玉芳\",\"deliveryOAaccount__c\":\"yufang2.zhu\",\"deliveryName__c\":\"朱玉芳-11194834\",\"ProjectPhase__c\":2,\"projectDeliveryType__c\":1,\"id\":\"3461249852185160\",\"PMOAAccount__c\":\"yufang2.zhu\"}";
        //pmsClientApi.upOpportunity(JSONObject.parseObject(jsonStr));

        // 查询订单数据
        //pmsClientApi.getOrderListByOpt("3393689823238720");

        // 直接查询概算数据
        //JSONObject response = PromotionApiUtil.getEstimateData("0060l00000UU8VdAAL02");
        //System.out.println("response = " + response);

        //JSONObject jsonObject = PromotionApiUtil.sendPmsGet(PromotionApiUtil.BUDGET_URL + "3570240797743763");
        //System.out.println("jsonObject = " + jsonObject);

        //  查询订单附件
        JSONObject propData = new JSONObject();
        propData.put("orderIds", "3693779822631569,3746032667122253,3741518809373339");
        ResultVo resultVo = pmsClientApi.getOrderAnnexByIds(propData);
        System.out.println("orderAnnexByIds = " + resultVo.getData());
    }


    /**
     * 获取订单附件
      * @param propData
     * @return
     */
    @RestMapping(value = "/getOrderAnnexByIds", method = RequestMethod.POST)
    public ResultVo getOrderAnnexByIds(@RestBeanParam(name = "body") JSONObject propData) {
        String LOGGER_MSG = "获取订单附件信息 ==> ";
        try {
            logger.info( LOGGER_MSG + "处理开始: " + propData);
            if (propData == null || propData.keySet().size() <= 0 || propData.getString("orderIds") == null) {
                logger.error( LOGGER_MSG + "传入数据异常: " + propData);
                return ResultVo.getFail("传入数据异常");
            }
            String orderIds = propData.getString("orderIds");
            if (orderIds.split(",").length > 50) {
                logger.error( LOGGER_MSG + "单词查询订单附件数量不可超过50");
                return ResultVo.getFail("单词查询订单附件数量不可超过50");
            }

            // 查询订单附件
            String sql = String.format("select id,oaApprovalFile__c,contractId.letter_entrusted__c letter_entrusted,contractId.invitation_notice__c invitation_notice," +
                    " contractId.letter_of_acceptance__c letter_of_acceptance from _order where id in (%s)", orderIds);
            List<JSONObject> orderData = XoqlService.instance().query(sql, true).getRecords();
            Map<String, Map<String, Object>> orderMap = new HashMap<>();
            for (JSONObject order : orderData) {
                Map<String, Object> fileMap = new HashMap<>();
                fileMap.put("orderId", order.getString("id")); // 合同扫描件
                fileMap.put("contractFile", order.getJSONArray("oaApprovalFile__c")); // 合同扫描件
                fileMap.put("letterEntrusted", order.getJSONArray("letter_entrusted")); // 提前入场实施委托函
                fileMap.put("invitationNotice", order.getJSONArray("invitation_notice")); // 邀请提前入场委托通知
                fileMap.put("letterOfAcceptance", order.getJSONArray("letter_of_acceptance")); // 中标通知书
                orderMap.put(order.getString("id"), fileMap);
            }
            System.out.println("orderMap = " + orderMap);
            return new ResultVo(200,"", orderMap);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error( LOGGER_MSG + "处理异常:" + e.getMessage());
            return  ResultVo.getFail(e.getMessage());
        }
    }

    /**
     * 查询订单数据
     * @param opportunityId
     * @return
     */
    @RestMapping(value = "/getOrderListByOpt", method = RequestMethod.GET)
    public ResultVo getOrderListByOpt(@RestQueryParam(name = "opportunityId") String opportunityId) {
        String LOGGER_MSG = "根据业务机会设置订单数据 ==> ";
        try {
            logger.info( LOGGER_MSG + "查询开始: " + opportunityId);
            if (opportunityId == null) {
                logger.info( LOGGER_MSG + "出入参数【业务机会】不可为空: " + opportunityId);
                return ResultVo.getFail("出入参数【业务机会】不可为空: " + opportunityId);
            }

            // 先获取业务机会数据 （为了兼容之前推的旧业务机会id）
            String sql = String.format("select id,opportunityName from opportunity where id = '%s' or SF_ID__c = '%s' ", opportunityId, opportunityId);
            Opportunity opportunity = hcxObjectService.queryOne(sql);
            if (opportunity == null) {
                logger.info(LOGGER_MSG + "没有找到对应的业务机会数据");
                return new ResultVo(-1,"没有找到对应的业务机会数据");
            }

            // 查询当前业务机会下的订单数据 返回字段: 机会点、合同号、合同审批状态(OA审批状态)、订单号、订单业务类型、订单审批状态(OA审批状态)、订单含税金额、订单不含税金额、订单创建时间
            logger.info( LOGGER_MSG + "opportunity: " + opportunity);
            Long optId = opportunity.getId();
            sql = "select id orderId,opportunityId,contractId.contractCode contractCode,contractId.oaApprovalStatus__c contractApprovalStatus," +
                    "po orderCode,entityType orderEntityType,oaApprovalStatus__c orderApprovalStatus,amount taxAmount,orderAmount__c noTaxAmount,createdAt orderCreateTime" +
                    " from _order where opportunityId = " + optId + " order by createdAt desc ";
            List<JSONObject> records = hcxObjectService.batchXoqlQuery(sql);
            System.out.println("records = " + records);
            logger.info( LOGGER_MSG + "records: " + records.size());

            logger.info(LOGGER_MSG + "查询成功");
            return new ResultVo(200,"", records);
        } catch (Exception e) {
            logger.error(LOGGER_MSG + "查询异常:" + e.getMessage());
            return new ResultVo(-1,"查询异常:" + e.getMessage());
        }
    }


    /**
     * 修改项目信息（PMS调用）
     * @param otiData
     * @return
     */
    @RestMapping(value = "/upOpportunity", method = RequestMethod.POST)
    public ResultVo upOpportunity(@RestBeanParam(name = "body") JSONObject otiData) {
        String LOGGER_MSG = "设置业务机会字段数据 ==> ";
        try {
            logger.info( LOGGER_MSG + "处理开始: " + otiData);
            if (otiData == null || otiData.keySet().size() <= 0 || otiData.getString("id") == null) {
                logger.error( LOGGER_MSG + "传入数据异常: " + otiData);
                return ResultVo.getFail("传入数据异常");
            }

            // 只更新最新阶段的项目数据：根据S(售前)-D(交付)-Q(质保)的顺序进行更新（如果当前是交付阶段，如果传过来的阶段是交付或质保才可进行更新，传过来的是售前则不进行更新）
            String opportunityId = otiData.getString("id");
            String sql = String.format("select id,ProjectPhase__c from opportunity where id = '%s' or SF_ID__c = '%s' ", opportunityId, opportunityId);
            Opportunity opportunity = hcxObjectService.queryOne(sql);
            if (opportunity == null) {
                logger.error( LOGGER_MSG + "找不到对应的业务机会数据");
                return ResultVo.getFail("找不到对应的业务机会数据");
            }
            Integer projectPhase = opportunity.getProjectPhase__c();
            Integer upProjectPhase = otiData.getInteger("ProjectPhase__c");
            if (projectPhase != null && upProjectPhase < projectPhase) {
                logger.info( LOGGER_MSG + "只更新最新阶段的项目数据");
                return ResultVo.getFail("只更新最新阶段的项目数据");
            }

            // 设置字段信息
            String pmsProjectCode = otiData.getString("pmsProjectCode__c");
            if (StringUtils.isNotBlank(pmsProjectCode)) {
                opportunity.setPmsProjectCode__c(pmsProjectCode); // PMS项目编码
            }

            opportunity.setProjectName__c(otiData.getString("projectName__c")); // 项目名称
            opportunity.setProjectPhase__c(upProjectPhase); // 项目阶段  1：售前  2：交付  3：质保
            opportunity.setPMOAAccount__c(otiData.getString("PMOAAccount__c")); // 项目经理OA账号
            opportunity.setPMName__c(otiData.getString("PMName__c")); // 项目经理姓名

            // 项目交付类型
            JSONArray projectType = ComUtils.getGlobalPicks("globalPick41__c"); // 获取 项目交付类型 通用选项集
            String projectDeliveryType = otiData.getString("projectDeliveryType__c");
            if (projectDeliveryType.length() == 1) {
                projectDeliveryType = "0" + projectDeliveryType;
            }
            opportunity.setProjectDeliveryType__c(ComUtils.getValueByApiKey(projectType, projectDeliveryType));

            // 项目状态
            String projectDeliveryDtatus = otiData.getString("ProjectDeliveryDtatus__c");
            logger.info( LOGGER_MSG + "projectDeliveryDtatus: " + projectDeliveryDtatus);
            if (StringUtils.isNotBlank(projectDeliveryDtatus)) {
                JSONObject optSelect = ComUtils.getEntityDesc("opportunity");
                Map<String, String> mapsFromDescribeJson = ComUtils.getMapsFromDescribeJson(optSelect, "ProjectDeliveryDtatus__c", false);
                String selVal = mapsFromDescribeJson.get(projectDeliveryDtatus);
                if (selVal != null) {
                    opportunity.setProjectDeliveryDtatus__c(Integer.valueOf(selVal));
                }
            }

            // PMS概算链接 如果传的是空不进行更新（只有售前阶段的有概算链接）
            String pmSbudgetLink = otiData.getString("PMSbudgetLink__c");
            if (StringUtils.isNotBlank(pmSbudgetLink)) {
                // 判断项目阶段
                if (upProjectPhase == 1) {
                    opportunity.setPMSbudgetLink__c(pmSbudgetLink); // 概算
                } else {
                    opportunity.setPMSbudgetLink2__c(pmSbudgetLink); // 预算
                }
            }

            // 根据负责人OA账号查找对应的用户id
            String deliveryOAaccount = otiData.getString("deliveryOAaccount__c");
            if (StringUtils.isNotBlank(deliveryOAaccount)) {
                opportunity.setDeliveryOAaccount__c(deliveryOAaccount); // 交付负责人OA账号：deliveryOAaccount__c  交付负责人姓名：deliveryName__c
                sql = String.format("select id,name,personalEmail,LoginName__c from user where personalEmail like '%s'", deliveryOAaccount + "%");
                List<JSONObject> userList = hcxObjectService.batchXoqlQuery(sql);
                if (userList.size() > 0) {
                    logger.info( LOGGER_MSG + "userList: " + userList);
                    opportunity.setDeliveryName__c(userList.get(0).getLong("id"));
                }
            }

            // 进行修改
            logger.info( LOGGER_MSG + "opportunity: " + opportunity);
            Boolean update = hcxObjectService.update(opportunity);
            logger.info( LOGGER_MSG + "update: " + update);

            logger.info(LOGGER_MSG + "处理成功");
            return new ResultVo(200,"");
        } catch (Exception e) {
            logger.error(LOGGER_MSG + "处理异常:" + e.getMessage());
            return new ResultVo(-1,"处理异常:" + e.getMessage());
        }
    }



    /**
     * 根据报价单获取PMS概算信息 报价单和订单两个使用场景, 默认是报价单，合同id不为空则是订单
     * @param quoteId
     * @return
     */
    @RestMapping(value = "/getPmsEstimateData", method = RequestMethod.GET)
    public String getPmsEstimateData(
            @RestQueryParam(name = "quoteId") Long quoteId,
            @RestQueryParam(name = "contractId") Long contractId,
            @RestQueryParam(name = "isTest") String isTest) {

        // 返回参数
        JSONObject result = new JSONObject();
        result.put("code", 200);
        result.put("msg", "");

        try {
            // 返回数据
            JSONObject resultData = new JSONObject();

            String sql = "";
            if (contractId != null) {
                // 查询订单需要的字段信息 获取合同下1号订单的详情数据
                sql = "select id,productId,productNameB__c,specificationModel__c,"+
                        "unitPrice,quantity2__c,unitA__c,SF_SL__c," +
                        "servicePeriod__c,subscription__c,subscriptionPeriod__c,subscriptionUntaxed__c " +
                        " from orderProduct where orderId.customItem210__c = 1 and customItem193__c = " + contractId;
                List<JSONObject> records = hcxObjectService.batchXoqlQuery(sql);

                // 新调整：不涉及概算数据，直接返回
                resultData.put("orderProductList", records);
                result.put("data", resultData);
                return result.toJSONString();
            }

            // 查询报价单需要的字段信息 获取报价单明细，查看是否已经有明细，有明细则不进行赋值操作
            resultData.put("isHasQuoteLine", "0");
            sql = "select id from quoteLine where quotationDetailEntityRelQuotationEntity = " + quoteId;
            XObject quoteLine = hcxObjectService.queryOne(sql);
            if (quoteLine != null) {
                resultData.put("isHasQuoteLine", "1");
            }

            // 根据报价单获取业务机会 ,quotationEntityRelOpportunity.ProjectPhase__c as projectPhase todo
            sql = "select id,quotationEntityRelOpportunity.opportunityName,quotationEntityRelOpportunity,quotationEntityRelOpportunity.SF_ID__c as sfId,quotationEntityRelOpportunity.ProjectPhase__c as projectPhase " +
                    " from quote where id = " + quoteId;
            JSONObject quote = hcxObjectService.batchXoqlQuery(sql).get(0);
            String opportunityId = quote.getString("quotationEntityRelOpportunity"); // 业务机会
            String opportunityIds = opportunityId;
            String sfId = quote.getString("sfId");
            if (StringUtils.isNotBlank(sfId)) {
                opportunityIds += "," + sfId;
            }

            // 判断当前用户是否是白名单用户
            resultData.put("isWhiteListUser", isWhiteListUser());

            // 测试使用模式数据
            if (StringUtils.isNotBlank(isTest)) {
                resultData.put("isWhiteListUser", "1"); // 是否是白名单用户
                opportunityIds = "3281374671051400";
            }
            logger.debug("resultData: " + resultData);

            // 获取概算信息：判断是否是交付阶段，如果是则获取预算数据，如果没有则还是取概算信息
            List<JSONObject> preEstimateList = new ArrayList<>();
            Integer projectPhase = quote.getInteger("projectPhase"); // 项目阶段 1: 售前  2：交付  3：质保
            logger.debug("projectPhase: " + projectPhase);
            if (projectPhase != null && projectPhase > 1) {
                // 获取业务机会下最新的订单id (查询系统中的预算，调整为下面接口实时获取)
                //sql = String.format("select customItem8__c from DeliveryListDetails__c where customItem8__c.opportunityId = %s order by createdBy desc limit 1", opportunityId);
                //List<JSONObject> tempList = hcxObjectService.batchXoqlQuery(sql);
                //if (tempList.size() > 0) {
                //    // 获取系统中回写的预算数据
                //    String ysSql = "select id,MaterialCode__c as productMaterialNo,TaxRate__c as taxRate,TotalPriceNOTax__c as totalPrice,TotalPriceInTax__c as totalPriceTax " +
                //            " from DeliveryListDetails__c where customItem8__c = " + tempList.get(0).getString("customItem8__c");
                //    preEstimateList = hcxObjectService.batchXoqlQuery(ysSql);
                //    logger.debug("系统的预算数据 preEstimateList: " + preEstimateList.size());
                //}

                // sfId 查询无数据再用 opportunityId 查询
                logger.debug("当前项目阶段为交付，查询预算信息");
                String optId = StringUtils.isNotBlank(sfId) ? sfId : opportunityId;
                JSONObject budgetData = PromotionApiUtil.sendPmsGet(PromotionApiUtil.BUDGET_URL + optId);
                if (budgetData.getJSONObject("data") == null && StringUtils.isNotBlank(sfId)) {
                    budgetData = PromotionApiUtil.sendPmsGet(PromotionApiUtil.BUDGET_URL + opportunityId);
                }

                logger.debug("接口实时获取预算数据: budgetData " + budgetData);
                JSONObject tempData = budgetData.getJSONObject("data");
                if (tempData != null && tempData.getString("preEstimateList") != null) {
                    preEstimateList = JSONArray.parseArray(tempData.getString("preEstimateList"), JSONObject.class);
                    resultData.put("isBudget", "1"); // 是否预算
                }
            }

            // 查询PMS概算数据
            if (preEstimateList.size() <= 0) {
                resultData.put("isBudget", "0"); // 是否预算
                JSONObject response = PromotionApiUtil.getEstimateData(opportunityIds);
                if (!Objects.equals(response.getInteger("code"),0)) {
                    logger.debug("查询机会PMS概算信息异常: " + response.getString("msg"));
                    result.put("code", -1);
                    result.put("msg", "查询机会PMS概算信息异常: " + response.getString("msg"));
                    return result.toJSONString();
                }

                // 获取数据
                JSONObject reqData = response.getJSONObject("data");
                preEstimateList = JSONArray.parseArray(reqData.getString("preEstimateList"), JSONObject.class);
                if (preEstimateList == null || preEstimateList.size() <= 0) {
                    logger.debug("概算产品明细为空");
                    result.put("code", -1);
                    result.put("msg", "概算产品明细为空");
                    result.put("data", resultData);
                    return result.toJSONString();
                }
            }

            // 获取税率通用选项集
            JSONArray taxRatePicks = ComUtils.getGlobalPicks("globalPick83__c");

            // 根据产品编码获取到CRM产品id
            String productMaterialNos = preEstimateList.stream().map(v -> "'" + v.getString("productMaterialNo") + "'").collect(Collectors.joining(","));
            sql = String.format("select id,productCode__c,productName from product where productStatus__c = 1 and productCode__c in (%s)", productMaterialNos);
            List<JSONObject> crmProductList = hcxObjectService.batchXoqlQuery(sql);

            // 赋值id
            for (JSONObject preEstimate : preEstimateList) {
                String productMaterialNo = preEstimate.getString("productMaterialNo");
                JSONObject product = crmProductList.stream().filter(v -> Objects.equals(v.getString("productCode__c"), productMaterialNo)).findFirst().orElse(null);
                if (product != null) {
                    preEstimate.put("productId", product.getLong("id"));
                    preEstimate.put("productMaterial", product.getString("productName"));
                }

                // 税率处理
                String taxRate = preEstimate.getString("taxRate");
                if (StringUtils.isNotBlank(taxRate)) {
                    taxRate = taxRate.replace("%", "");
                    preEstimate.put("taxRateVal", ComUtils.getGeneralValue(taxRatePicks, taxRate));
                }
            }

            resultData.put("preEstimateList", preEstimateList);
            result.put("data", resultData);
            return result.toJSONString();
        } catch (Exception e) {
            e.printStackTrace();
            result.put("code", -1);
            result.put("msg", "查询机会PMS概算信息异常: " + e.getMessage());
            return result.toJSONString();
        }
    }


    /**
     * 是否是白名单用户
     * @return
     * @throws ApiEntityServiceException
     */
    public String isWhiteListUser() throws IOException, XsyHttpException {
        String isWhiteUser = "0";
        ScriptRuntimeContext src = ScriptRuntimeContext.instance();
        long userId = src.getUserId();
        logger.debug("userId: " + userId);
        if (userId != -1) {
            JSONObject responseData = ComUtils.queryUserRole(userId);
            List<JSONObject> userRoleLists = JSONArray.parseArray(responseData.getString("records"), JSONObject.class);
            logger.debug("userRoleLists: " + userRoleLists);

            // 判断是否是这两个角色的用户 管理员: 160401000 测试管理员:3398945251760733 商务: 3214956314643734 报价单测试:3440442528242323
            List<Long> roleList = Arrays.asList(160401000L, 3398945251760733L, 3214956314643734L, 3440442528242323L);
            for (JSONObject userRoleList : userRoleLists) {
                if (roleList.contains(userRoleList.getLong("id"))) {
                    isWhiteUser = "1";
                    return isWhiteUser;
                }
            }
        }
        return isWhiteUser;
    }


    /**
     * 设置项目应收信息
     * @param receivableData
     * @return
     */
    @RestMapping(value = "/setProjectReceivables", method = RequestMethod.POST)
    public ResultVo setProjectReceivables(@RestBeanParam(name = "body") JSONObject receivableData) {
        String LOGGER_MSG = "设置项目应收信息 ==> ";
        try {
            logger.info( LOGGER_MSG + "处理开始: " + receivableData);
            if (receivableData == null || receivableData.keySet().size() <= 0) {
                logger.info( LOGGER_MSG + "传入数据异常: " + receivableData);
                return ResultVo.getFail("传入数据异常: " + receivableData);
            }

            // 根据项目编号查询订单下的明细数据 (只获取1号订单)
            Set<String> pmsProjectNoSet = receivableData.keySet();
            String pmsProjectNos = pmsProjectNoSet.stream().map(v -> "'" + v + "'").collect(Collectors.joining(","));
            String sql = "select id,orders__c.pmsProjectNoA__c pmsProjectNoA__c,dueDate__c,receivablePhase__c " +
                    "from receivablesDetails__c where receivablePhase__c is not null and orders__c.customItem210__c = 1 and orders__c.pmsProjectNoA__c in (" + pmsProjectNos + ")";

            List<JSONObject> receivablesList = hcxObjectService.batchXoqlQuery(sql);
            logger.info( LOGGER_MSG + "receivablesList: " + receivablesList.size());
            if (receivablesList.size() <= 0) {
                logger.info( LOGGER_MSG + "当前项目编号查询不到对应的订单应收明细数据，无需处理");
                return ResultVo.getSuccess("当前项目编号查询不到对应的订单应收明细数据，无需处理");
            }

            // 处理数据
            List<ReceivablesDetails__c> batchUpReceivablesList = new ArrayList<>();
            for (String key : receivableData.keySet()) {

                // 跟进项目编号查找到对应的应收明细
                List<JSONObject> filterReceivablesList = receivablesList.stream().filter(v -> Objects.equals(key, v.getString("pmsProjectNoA__c"))).collect(Collectors.toList());

                // 根据里程碑找到匹配的应收明细 给日期进行赋值
                List<JSONObject> detailList = JSONArray.parseArray(receivableData.get(key).toString(), JSONObject.class);
                logger.info( LOGGER_MSG + "detailList: " + key + " ==> " + detailList.size());
                for (JSONObject receivableDetail : detailList) {
                    String milestoneName = receivableDetail.getString("milestoneName");

                    // 根据名称进行匹配  应收计划  1:预付 * 2：蓝图 3：上线 4：初验 5：终验 6：质保 7：其他 *
                    switch (milestoneName) {
                        case "蓝图确认":
                            // 对应CRM 蓝图确认 2
                            batchUpReceivablesList.addAll(getUpReceivablesList(filterReceivablesList, Arrays.asList(2), receivableDetail));
                            break;
                        case "系统上线":
                            // 对应CRM 系统上线 3
                            batchUpReceivablesList.addAll(getUpReceivablesList(filterReceivablesList, Arrays.asList(3), receivableDetail));
                            break;
                        case "项目验收":
                            // 对应CRM 系统上线  初验、终验  4\5
                            batchUpReceivablesList.addAll(getUpReceivablesList(filterReceivablesList, Arrays.asList(4,5), receivableDetail));
                            break;
                        case "项目转质保/关闭":
                            // 对应CRM 质保 6
                            batchUpReceivablesList.addAll(getUpReceivablesList(filterReceivablesList, Arrays.asList(6), receivableDetail));
                            break;
                    }

                }

                // 进行保存
                if (batchUpReceivablesList.size() > 50) {
                    Boolean update = hcxObjectService.batchUpdate(batchUpReceivablesList);
                    if (!update) {
                        logger.error( LOGGER_MSG + "update: " + update);
                    }
                    batchUpReceivablesList.clear();
                }
            }

            // 更新应收明细数据
            logger.info( LOGGER_MSG + "batchUpReceivablesList: " + batchUpReceivablesList);
            if (batchUpReceivablesList.size() > 0) {
                Boolean update = hcxObjectService.batchUpdate(batchUpReceivablesList);
                if (!update) {
                    logger.error( LOGGER_MSG + "batchUpReceivablesList: " + update);
                }
            }

            logger.info(LOGGER_MSG + "处理成功");
            return new ResultVo(200,"");
        } catch (Exception e) {
            logger.error(LOGGER_MSG + "处理异常:" + e.getMessage());
            return new ResultVo(-1,"处理异常:" + e.getMessage());
        }
    }

    /**
     * 获取修改的应收明细数据
     * @param filterReceivablesList
     * @param nodeList
     * @param receivableDetail
     * @return
     */
    public List<ReceivablesDetails__c> getUpReceivablesList(List<JSONObject> filterReceivablesList, List<Integer> nodeList, JSONObject receivableDetail) {
        // CRM计划应收日期-PMS计划完成时间 CRM实际应收日期-PMS实际完成时间
        Long actualFinishTime = receivableDetail.getLong("actualFinishTime"); // 实际完成时间
        Long planFinishTime = receivableDetail.getLong("planFinishTime"); // 计划完成时间

        List<ReceivablesDetails__c> receivablesList = new ArrayList<>();
        filterReceivablesList.stream().filter(v -> nodeList.contains(v.getInteger("receivablePhase__c"))).forEach(v -> {
            ReceivablesDetails__c receivablesDetails = new ReceivablesDetails__c();
            receivablesDetails.setId(v.getLong("id"));
            receivablesDetails.setDueDate__c(planFinishTime); // 计划应收日期
            receivablesDetails.setActualDate__c(actualFinishTime); // 实际应收时间
            receivablesList.add(receivablesDetails);
        });
        return receivablesList;
    }


    /**
     * 订单赋值PMS项目预算信息
     * @param projectData
     * @return
     */
    @RestMapping(value = "/projectBudget", method = RequestMethod.POST)
    public ResultVo setOrderBudgetInfo(@RestBeanParam(name = "body") JSONObject projectData) {
        String LOGGER_MSG = "同步PMS订单预算信息 ==> ";
        try {
            logger.info(LOGGER_MSG + "处理开始: " + projectData);
            String deliveryNo = projectData.getString("deliveryNo");
            if (deliveryNo == null) {
                logger.info(LOGGER_MSG + "【deliveryNo】项目编码不可为空");
                return new ResultVo(-1,"【deliveryNo】项目编码不可为空");
            }

            // 先获取业务机会数据
            String sql = String.format("select id from opportunity where pmsProjectCode__c = '%s'", deliveryNo);
            Opportunity opportunity = hcxObjectService.queryOne(sql);
            if (opportunity == null) {
                logger.info(LOGGER_MSG + "没有找到对应的业务机会数据");
                return new ResultVo(-1,"没有找到对应的业务机会数据");
            }

            // 获取交付清单明细
            List<JSONObject> preEstimateList = JSONArray.parseArray(projectData.getString("preEstimateList"), JSONObject.class);
            String saleContractNos = preEstimateList.stream().map(v -> "'" + v.getString("saleContractNo") + "'").collect(Collectors.joining(","));

            // 关联到对应的订单
            String orderId = projectData.getString("orderId");
            Long opportunityId = opportunity.getId();
            sql = String.format("select id,po from _order where opportunityId = %s and po in (%s)", opportunityId, saleContractNos);
            List<Order> orderList = hcxObjectService.query(sql, Order.class);
            logger.info(LOGGER_MSG + "orderId: " + orderId);
            logger.info(LOGGER_MSG + "orderList: " + orderList.size());
            if (orderList.size() <= 0) {
                logger.info(LOGGER_MSG + "当前机会点没有订单数据");
                return new ResultVo(200,"当前机会点没有订单数据，无需处理");
            }

            // 保存订单信息
            List<DeliveryListDetails__c> addDeliveryListDetailsList = new ArrayList<>();
            for (Order order : orderList) {

                // 订单主表
                order.setProjectGrossProfit__c(projectData.getDouble("grossProfitCount")); // 项目总毛利
                order.setProjectGrossProfitMargin__c(projectData.getDouble("grossProfitMarginCount")); // 项目总毛利率
                order.setProjectContributionProfit__c(projectData.getDouble("projectContributionRate")); // 项目总贡献利润 ProjectContributionProfit__c
                order.setProjectContributionProfitMargin__c(projectData.getDouble("netProfitContributedByTheProject")); // 项目总贡献利润率 ProjectContributionProfitMargin__c

                // 交付清单明细
                List<JSONObject> filterList = preEstimateList.stream().filter(v -> Objects.equals(v.getString("saleContractNo"), order.getPo())).collect(Collectors.toList());
                for (int i = 0; i < filterList.size(); i++) {
                    JSONObject preEstimate = filterList.get(i);
                    DeliveryListDetails__c deliveryListDetails = new DeliveryListDetails__c();
                    deliveryListDetails.setEntityType(3294436727626374L);
                    deliveryListDetails.setName(String.valueOf(i + 1));
                    deliveryListDetails.setCustomItem8__c(order.getId()); // 主子明细
                    deliveryListDetails.setMaterialCode__c(preEstimate.getString("productMaterialNo")); // 物料编码
                    deliveryListDetails.setMaterialDescription__c(preEstimate.getString("productMaterial")); // 物料描述
                    deliveryListDetails.setTaxRate__c(preEstimate.getString("taxRate")); // 税率
                    deliveryListDetails.setContractNumber__c(preEstimate.getString("saleContractNo")); // 合同编号
                    deliveryListDetails.setTotalPriceNOTax__c(preEstimate.getDouble("totalPrice")); // 产品总价-不含税
                    deliveryListDetails.setTotalPriceInTax__c(preEstimate.getDouble("totalPriceTax")); // 产品总价-含税
                    addDeliveryListDetailsList.add(deliveryListDetails);
                }

            }

            // 保存前清空现有的交付清单明细
            String orderIds = orderList.stream().map(v -> v.getId().toString()).collect(Collectors.joining(","));
            sql = "select id from DeliveryListDetails__c where customItem8__c in (" + orderIds + ")";
            List<DeliveryListDetails__c> deliveryListDetailsList = hcxObjectService.query(sql, DeliveryListDetails__c.class);
            if (deliveryListDetailsList.size() > 0) {
                logger.info(LOGGER_MSG + "处理成功");
                Boolean batchDelete = hcxObjectService.batchDelete(deliveryListDetailsList);
                if (!batchDelete) {
                    logger.error(LOGGER_MSG + "批量删除交付清单明细异常");
                    return new ResultVo(-1,"批量删除交付清单明细异常");
                }
            }

            // 保存
            Boolean update = hcxObjectService.batchUpdate(orderList);
            if (!update) {
                logger.error(LOGGER_MSG + "保存订单预算信息异常");
                return new ResultVo(-1,"保存订单预算信息异常");
            }

            // 新增交付清单明细
            BatchOperateResult batchOperateResult = hcxObjectService.batchInsert(addDeliveryListDetailsList);
            if (!batchOperateResult.getSuccess()) {
                logger.error(LOGGER_MSG + "新增交付清单明细异常");
                return new ResultVo(-1,"新增交付清单明细异常");
            }

            logger.info(LOGGER_MSG + "处理成功");
            return new ResultVo(200,"");
        } catch (Exception e) {
            logger.error(LOGGER_MSG + "处理异常:" + e.getMessage());
            return new ResultVo(-1,"处理异常:" + e.getMessage());
        }
    }


}
